package com.lucifer.hawkeye.ai.service.impl;

import com.lucifer.hawkeye.ai.common.response.MessageWrapper;
import com.lucifer.hawkeye.ai.common.response.RestResult;
import com.lucifer.hawkeye.ai.domain.conversation.bo.ChatConversationBo;
import com.lucifer.hawkeye.ai.domain.conversation.bo.ChatMemoryBo;
import com.lucifer.hawkeye.ai.domain.conversation.type.ConversationType;
import com.lucifer.hawkeye.ai.domain.conversation.vo.ConversationVO;
import com.lucifer.hawkeye.ai.service.ConversationService;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.messages.MessageType;
import org.springframework.ai.document.id.RandomIdGenerator;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author lucifer
 * @date 2025/4/1 14:23
 */
@Service
public class ConversationServiceImpl implements ConversationService {

    @Resource(name = "pgJdbcTemplate")
    private JdbcTemplate pgJdbcTemplate;


    @Override
    public RestResult create(String conversationType) {
        if(!ConversationType.check(conversationType)){
            return RestResult.buildSuccessResult("conversationType is not correct");
        }
        ConversationType.check(conversationType);
        String title = ConversationType.codeOf(conversationType).getName();
        String id = new RandomIdGenerator().generateId();
        pgJdbcTemplate.update("insert into chat_conversation(id,title,create_time,update_time,conversation_type) values(?,?,?,?,?)", id, title, new Date(), new Date(),conversationType);
        ConversationVO conversationVO = ConversationVO.builder().conversationId(id)
                .title(title)
                .conversationType(conversationType)
                .build();

        return RestResult.buildSuccessResult(conversationVO);
    }

    @Override
    public RestResult edit(String conversationId, String title) {
        if (!StringUtils.hasText(title)) {
            return RestResult.buildSuccessResult();
        }
        pgJdbcTemplate.update("UPDATE chat_conversation SET title = ?, update_time = ? WHERE id = ?", title, new Date(), conversationId);
        return RestResult.buildSuccessResult();
    }

    @Override
    public RestResult list() {
        BeanPropertyRowMapper<ChatConversationBo> mapper = new BeanPropertyRowMapper<>(ChatConversationBo.class);
        List<ChatConversationBo> chatMemoryBoList = pgJdbcTemplate.query("select id,title,conversation_type from chat_conversation", mapper);
        List<ConversationVO> list = Optional.ofNullable(chatMemoryBoList).orElse(List.of())
                .stream()
                .map(chatConversationBo -> {
                    return ConversationVO.builder().conversationId(chatConversationBo.getId())
                            .title(chatConversationBo.getTitle())
                            .conversationType(chatConversationBo.getConversation_type())
                            .build();
                }).collect(Collectors.toList());
        return RestResult.buildSuccessResult(list);
    }

    @Override
    public RestResult get(String conversationId) {
        BeanPropertyRowMapper<ChatConversationBo> mapper = new BeanPropertyRowMapper<>(ChatConversationBo.class);
        ChatConversationBo conversationBo = pgJdbcTemplate.queryForObject("SELECT id, title,conversation_type FROM chat_conversation WHERE id = ?", mapper, conversationId);

        BeanPropertyRowMapper<ChatMemoryBo> chatMemoryBoBeanPropertyRowMapper = new BeanPropertyRowMapper<>(ChatMemoryBo.class);
        List<ChatMemoryBo> chatMemoryBoList = pgJdbcTemplate.query("SELECT id, content, metadata AS metadataJson, embedding FROM chat_memory WHERE metadata->>'conversationId' = ? ORDER BY (metadata ->> 'created_at')::bigint", chatMemoryBoBeanPropertyRowMapper, conversationId);


        ChatMemoryBo nl2SqlBo = new ChatMemoryBo();
        Map<String, Object> nl2SqlMetadata = Maps.newHashMap();
        if(Objects.equals(conversationBo.getConversation_type(),ConversationType.NL2SQL.getCode())){
            BeanPropertyRowMapper<ChatMemoryBo> nl2SqlBoBeanPropertyRowMapper = new BeanPropertyRowMapper<>(ChatMemoryBo.class);
            nl2SqlBo = pgJdbcTemplate.queryForObject("SELECT id, content, metadata AS metadataJson, embedding FROM nl2sql_store WHERE metadata->>'conversationId' = ? AND metadata->>'rag_type' = 'DDL'", nl2SqlBoBeanPropertyRowMapper, conversationId);
            nl2SqlBo = new ChatMemoryBo(nl2SqlBo);
            nl2SqlMetadata = nl2SqlBo.getMetadata();
        }

        List<MessageWrapper> messages = Optional.ofNullable(chatMemoryBoList).orElse(Lists.newArrayList())
                .stream()
                .map(chatMemoryBo -> {
                    ChatMemoryBo memoryBo = new ChatMemoryBo(chatMemoryBo);
                    Map<String, Object> metadata = memoryBo.getMetadata();
                    MessageWrapper messageWrapper = new MessageWrapper();
                    messageWrapper.setContent(memoryBo.getContent());
                    messageWrapper.setType(MessageType.valueOf((String) metadata.get("messageType")));
                    return messageWrapper;
                }).collect(Collectors.toList());

        String nl2sqlTrainType = (String) nl2SqlMetadata.get("rag_type");

        ConversationVO conversationVO = ConversationVO.builder().conversationId(conversationId)
                .title(conversationBo.getTitle())
                .conversationType(conversationBo.getConversation_type())
                .nl2sqlQuestion((String) nl2SqlMetadata.get("semantic"))
                .nl2sqlContent(Objects.equals("SQL",nl2sqlTrainType) ? JSONObject.parseObject(nl2SqlBo.getContent()).getString("sql"): nl2SqlBo.getContent())
                .nl2sqlTrainType(nl2sqlTrainType)
                .datasource((String) nl2SqlMetadata.get("datasource"))
                .tableName((String) nl2SqlMetadata.get("table_name"))
                .messages(messages)
                .build();
        return RestResult.buildSuccessResult(conversationVO);
    }

    @Override
    public RestResult del(String conversationId) {
        pgJdbcTemplate.update("delete from  chat_conversation where id = ?", conversationId);
        return RestResult.buildSuccessResult();
    }
}
